﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using BrnMall.WeiXin.Sdk.Domain;
using Newtonsoft.Json;
using WeiTap.Web;
using WeiTap.Web.Params;
using System.Web;
using BrnMall.Sdk.WeiXin.Tool;

namespace BrnMall.WeiXin.Sdk
{
    public static class WeiXinSdk
    {
        /// <summary>
        /// 获取access_token
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secret"></param>
        /// <returns></returns>
        public static AccessToken GetAccessToken(string appId, string secret)
        {
            if(string.IsNullOrEmpty(appId))
                throw new ArgumentNullException(nameof(appId));
            if(string.IsNullOrEmpty(secret))
                throw new ArgumentNullException(nameof(secret));
            try
            {
                var url =
                    $"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={secret}";
                var www=new HttpFire(url){Method = HttpRequestMethod.Get};
                var r = www.GetString();
                Trace.TraceInformation(r);
                var result = JsonConvert.DeserializeObject<AccessToken>(r);
                return result;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.Message);
                throw;
            }
        }

        public static SessionResult GetSessionResult(string code, string appId, string secret)
        {
            if (string.IsNullOrEmpty(code))
                throw new ArgumentNullException(nameof(code));
            if (string.IsNullOrEmpty(appId))
                throw new ArgumentNullException(nameof(appId));
            if (string.IsNullOrEmpty(secret))
                throw new ArgumentNullException(nameof(secret));
            try
            {
                var url =
                    "https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+secret+"&js_code="+code+"&grant_type=authorization_code";
                
                var www = new HttpFire(url) {Method = HttpRequestMethod.Get};
                var r = www.GetString();
                Trace.TraceInformation(r);
                var result = JsonConvert.DeserializeObject<SessionResult>(r);
                return result;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.StackTrace);
                throw;
            }
        }
        /// <summary>
        /// 小程序第三方平台登录接口
        /// </summary>
        /// <param name="appId">小程序ID</param>
        /// <param name="code"></param>
        /// <param name="componentAppid">第三方平台appid</param>
        /// <param name="componentAccessToken">第三方平台的component_access_token</param>
        /// <returns></returns>
        public static SessionResult GetSessionResult(string appId, string code, string componentAppid,string componentAccessToken)
        {
            if (string.IsNullOrEmpty(code))
                throw new ArgumentNullException(nameof(code));
            if (string.IsNullOrEmpty(appId))
                throw new ArgumentNullException(nameof(appId));
            if (string.IsNullOrEmpty(componentAppid))
                throw new ArgumentNullException(nameof(componentAppid));
            if (string.IsNullOrEmpty(componentAccessToken))
                throw new ArgumentNullException(nameof(componentAccessToken));
            try
            {
                var url =
                    $"https://api.weixin.qq.com/sns/component/jscode2session?appid={appId}&js_code={code}&grant_type=authorization_code&component_appid={componentAppid}&component_access_token={componentAccessToken}";

                var www = new HttpFire(url) { Method = HttpRequestMethod.Get };
                var r = www.GetString();
                Trace.TraceInformation(r);
                var result = JsonConvert.DeserializeObject<SessionResult>(r);
                return result;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.StackTrace);
                throw;
            }
        }
        /// <summary>
        /// 解密用户信息
        /// </summary>
        /// <param name="sessionKey"></param>
        /// <param name="encryptedData"></param>
        /// <param name="iv"></param>
        /// 
        /// <returns></returns>
        public static WXUserInfo DecryptUserInfo(string sessionKey, string encryptedData, string iv)
        {
            var tkey = Convert.FromBase64String(sessionKey);
            var tdata = Convert.FromBase64String(encryptedData);
            var tiv = Convert.FromBase64String(iv);
            using (var aes = new AesCryptoServiceProvider())
            {
                aes.IV = tiv;
                aes.Mode=CipherMode.CBC;
                aes.Padding=PaddingMode.PKCS7;
                aes.Key = tkey;
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(tdata,0,tdata.Length);
                        cs.FlushFinalBlock();
                    }
                    var r = ms.ToArray();
                    var jsonString = Encoding.UTF8.GetString(r);
                    return JsonConvert.DeserializeObject<WXUserInfo>(jsonString);
                }
            }
        }

        /// <summary>
        /// 获取小程序码A接口
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="secret"></param>
        /// <param name="pathString"></param>
        /// <returns></returns>
        public static string GetWxaCode(string appId, string secret,string pathString)
        {
            try
            {
                var ak = GetAccessToken(appId, secret);
                return GetWxaCodeByAccessToken(ak.Access_Token, pathString);
            }
            catch (Exception e)
            {
                Trace.TraceError(e.Message);
                throw;
            }
        }

        public static string GetWxaCodeByAccessToken(string accessToken,string pathString)
        {
            try
            {
              
                var url = $"https://api.weixin.qq.com/wxa/getwxacode?access_token={accessToken}";

                var request = (HttpWebRequest)WebRequest.Create(url);
                var message = new
                {
                    path = pathString,
                    width = 430,
                    auto_color = true
                };
                var postData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(message));
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = postData.Length;
                using (var stream = request.GetRequestStream())
                {
                    stream.Write(postData, 0, postData.Length);
                }
                var response = (HttpWebResponse)request.GetResponse();
                var resStream = response.GetResponseStream();
                if (resStream == null) return string.Empty;
                var dirPath = GetMapPath("/upload/user/");
                var newFileName = $"acode_{DateTime.Now:yyMMddHHmmssfffffff}.jpg";
                var savePath = dirPath + newFileName;
                if (!Directory.Exists(dirPath))
                    Directory.CreateDirectory(dirPath);
                using (var fs = new FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                {
                    byte[] buff = new byte[512];
                    int c = 0; //实际读取的字节数
                    while ((c = resStream.Read(buff, 0, buff.Length)) > 0)
                    {
                        fs.Write(buff, 0, c);
                    }
                }
                return savePath;
            }
            catch (Exception e)
            {
                Trace.TraceError(e.Message);
                throw;
            }
        }

        public static string GetMapPath(string path)
        {
            return HttpContext.Current != null ? HttpContext.Current.Server.MapPath(path) : System.Web.Hosting.HostingEnvironment.MapPath(path);
        }

        #region 第三方平台相关api

        public static ComponentAccessTokenResponse GetComponentAccessTokenResponse(ComponentAccessTokenPostData data)
        {
            const string url = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";

            var request = (HttpWebRequest)WebRequest.Create(url);
            
            var postData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = postData.Length;
            using (var stream = request.GetRequestStream())
            {
                stream.Write(postData, 0, postData.Length);
            }
            var response = (HttpWebResponse)request.GetResponse();
            var resStream = response.GetResponseStream();
            if (resStream == null) return new ComponentAccessTokenResponse();
            var wwwresult = new StreamReader(resStream).ReadToEnd();
            return JsonConvert.DeserializeObject<ComponentAccessTokenResponse>(wwwresult);
        }

        public static GetPreAuthCodeResponse GetPreAuthCodeResponse(string componentAppid,string componentAccessToken)
        {
            var url = $"https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token={componentAccessToken}";
            var postData = $"{{\"component_appid\":\""+componentAppid+"\"}}";
            return RestHttp.Post<GetPreAuthCodeResponse>(url, postData);
        }

        #endregion
        #region 获取小程序授权信息

        public static AuthorizationResponse GetAuthorization(string componentAccessToken, string componentAppid,
            string authorizationCode)
        {
            var url =
                $"https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token={componentAccessToken}";
            var request = (HttpWebRequest)WebRequest.Create(url);
            var postData = $"{{\"component_appid\":\"{componentAppid}\",\"authorization_code\": \"{authorizationCode}\"}}";
            return RestHttp.Post<AuthorizationResponse>(url, postData);

        }
        /// <summary>
        /// 刷新用户小程序令牌
        /// </summary>
        /// <param name="componentAccessToken"></param>
        /// <param name="componentAppid"></param>
        /// <param name="authorizerAppid"></param>
        /// <param name="authorizerRefreshToken"></param>
        /// <returns></returns>
        public static RefreshAuthorizerTokenResponse RefreshAuthorizerToken(string componentAccessToken, string componentAppid,
            string authorizerAppid, string authorizerRefreshToken)
        {
            var url =
                $"https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token?component_access_token={componentAccessToken}";
            var postData=$"{{\"component_appid\":\"{componentAppid}\",\"authorizer_appid\":\"{authorizerAppid}\",\"authorizer_refresh_token\":\"{authorizerRefreshToken}\"}}";
            return RestHttp.Post<RefreshAuthorizerTokenResponse>(url, postData);
        }
        /// <summary>
        /// 获取授权人的基本信息
        /// </summary>
        /// <param name="componentAccessToken"></param>
        /// <param name="componentAppid"></param>
        /// <param name="authorizerAppid"></param>
        /// <returns></returns>
        public static AuthorizerInfoResponse GetAuthorizationInfo(string componentAccessToken,
            string componentAppid, string authorizerAppid)
        {
            var url = $"https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token={componentAccessToken}";
            var postData = $"{{\"component_appid\":\"{componentAppid}\",\"authorizer_appid\": \"{authorizerAppid}\"}}";
            return RestHttp.Post<AuthorizerInfoResponse>(url, postData);
        }

        #endregion
    }
}
